package cn.gyouzhe.component.taobao;

import cn.gyouzhe.config.props.TaobaoProperties;
import cn.gyouzhe.utils.Url;
import cn.gyouzhe.vo.GoodVo;
import cn.gyouzhe.vo.PageResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.taobao.api.ApiException;
import com.taobao.api.DefaultTaobaoClient;
import com.taobao.api.TaobaoClient;
import com.taobao.api.request.TbkSpreadGetRequest;
import com.taobao.api.request.WirelessShareTpwdQueryRequest;
import com.taobao.api.response.TbkSpreadGetResponse;
import com.taobao.api.response.WirelessShareTpwdQueryResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 淘宝组件
 *
 * @author wangchuan
 * @datetime 2017/12/25 21:23
 */
@Slf4j
@Component
public class TaobaoComponent {
    private static final String ALIMAMA_SEARCH_URL = "http://pub.alimama.com/items/search.json";
    /**
     * h5appkey
     */
    private static final String H5APPKEY = "12574478";
    /**
     * H5version
     */
    private static final String VERSION = "1.0";

    @Autowired
    private TaobaoProperties taobaoProperties;

    private TaobaoClient taobaoClient;
    /**
     * 请求cookie存储器
     */
    private CookieStore cookieStore;
    private HttpClient hasCookieHttpClient;

    private HttpClient noCookieHttpClient;


    /**
     * taobaoclient
     *
     * @return
     */
    private TaobaoClient getTaobaoClient() {
        if(null == taobaoClient) {
            synchronized(this) {
                if(null == taobaoClient) {
                    taobaoClient = new DefaultTaobaoClient(taobaoProperties.getUrl(), taobaoProperties.getAppKey(), taobaoProperties.getAppSecret());
                }
            }
        }
        return taobaoClient;
    }

    /**
     * 获取有cookie请求CLIENT
     *
     * @return httpclient
     */
    private HttpClient getHasCookieHttpClient() {
        if(null == hasCookieHttpClient) {
            synchronized(this) {
                if(null == hasCookieHttpClient) {
                    cookieStore = new BasicCookieStore();
                    hasCookieHttpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();
                }
            }
        }
        return hasCookieHttpClient;
    }

    /**
     * 获取无cookie请求CLIENT
     *
     * @return httpclient
     */
    private HttpClient getNoCookieHttpClient() {
        if(null == noCookieHttpClient) {
            synchronized(this) {
                if(null == noCookieHttpClient) {
                    noCookieHttpClient = HttpClientBuilder.create().build();
                }
            }
        }
        return noCookieHttpClient;
    }

    /**
     * 生成淘宝商品链接
     *
     * @param goodId 商品ID
     * @param tmall  是否是天猫
     * @return 链接地址
     */
    private String generateTaobaoUrl(String goodId, boolean tmall) {
        String taobaoUrl = "https://item.taobao.com/item.htm?id=%s";
        String tmallUrl = "https://detail.tmall.com/item.htm?id=%s";
        return String.format(tmall ? tmallUrl : taobaoUrl, goodId);
    }

    /**
     * 获取H5请求票据
     * @return
     */
    private String getH5Ticket() {
        if(null != cookieStore) {
            List<Cookie> cookies = cookieStore.getCookies();
            if(!cookies.isEmpty()) {
                for(Cookie cookie : cookies) {
                    String name = cookie.getName();
                    if(StringUtils.equals(name, "_m_h5_tk")) {
                        String value = cookie.getValue();
                        return StringUtils.split(value, "_")[0];
                    }
                }
            }
        }
        return null;
    }

    /**
     * 转成短链
     *
     * @param url
     * @return
     */
    public String spread(String url) {
        try {
            TbkSpreadGetRequest tbkSpreadGetRequest = new TbkSpreadGetRequest();
            List<TbkSpreadGetRequest.TbkSpreadRequest> requests = new ArrayList<>();
            TbkSpreadGetRequest.TbkSpreadRequest tbkSpreadRequest = new TbkSpreadGetRequest.TbkSpreadRequest();
            tbkSpreadRequest.setUrl(url);
            requests.add(tbkSpreadRequest);
            tbkSpreadGetRequest.setRequests(requests);
            TbkSpreadGetResponse response = getTaobaoClient().execute(tbkSpreadGetRequest);
            if(response.isSuccess()) {
                return response.getResults().get(0).getContent();
            }
        } catch(ApiException e) {
            log.error("转短链失败", e);
        }
        return null;
    }


    /**
     * H5请求
     *
     * @param api  请求API
     * @param data 请求数据
     * @return 返回内容
     */
    public String h5Request(String api, String data) {
        String content = null;
        try {
            do {
                String h5tk = getH5Ticket();
                StringBuilder urlBuilder = new StringBuilder("https://acs.m.taobao.com/h5/" + api + "/1.0/?type=json&api=" + api + "&v=" + VERSION);
                long millis = System.currentTimeMillis();
                String sign = DigestUtils.md5Hex(h5tk + "&" + millis + "&" + H5APPKEY + "&" + data);
                urlBuilder.append("&appKey=").append(H5APPKEY)
                        .append("&sign=").append(sign)
                        .append("&t=").append(millis)
                        .append("&data=").append(URLEncoder.encode(data, "UTF-8"));
                HttpGet httpGet = new HttpGet(urlBuilder.toString());
                HttpResponse response = getHasCookieHttpClient().execute(httpGet);
                int statuCode = response.getStatusLine().getStatusCode();
                HttpEntity httpEntity = response.getEntity();
                if(null != httpEntity)
                    content = EntityUtils.toString(httpEntity, "UTF-8");
                if(statuCode == 200) {
                    if(!StringUtils.contains(content, "令牌为空") && !StringUtils.contains(content, "非法请求"))
                        break;
                    if(StringUtils.isNotEmpty(h5tk))
                        log.error("请求H5接口失败,返回状态为：{},返回结果为：{}", statuCode, content);
                } else {
                    log.error("请求H5接口失败,返回状态为：{},返回结果为：{}", statuCode, content);
                    break;
                }
            } while(true);
        } catch(UnsupportedEncodingException e) {
            log.error("编码数据异常", e);
        } catch(ClientProtocolException e) {
            log.error("请求协议异常", e);
        } catch(IOException e) {
            log.error("IO异常", e);
        }
        return content;
    }

    /**
     * 淘口令解析
     *
     * @param tbwd 包含淘口令的字符
     */
    public void tbwdQuery(String tbwd) {
        try {
            WirelessShareTpwdQueryRequest wirelessShareTpwdQueryRequest = new WirelessShareTpwdQueryRequest();
            wirelessShareTpwdQueryRequest.setPasswordContent(tbwd);
            WirelessShareTpwdQueryResponse response = getTaobaoClient().execute(wirelessShareTpwdQueryRequest);
            System.out.println(response.getBody());
        } catch(ApiException e) {
            log.error("解析淘口令异常", e);
        }
    }

    /**
     * 获取PID
     * @return 个人PID
     */
    public String pid() {
        return taobaoProperties.getPid();
    }

    /**
     * 格式化返回结果
     * @param content
     * @return
     */
    private PageResult<GoodVo> formatContent(String content) {
        if(StringUtils.isNotEmpty(content) && StringUtils.contains(content, "\"status\":\"OK\"")) {
            JSONObject jsonObject = JSON.parseObject(content);
            JSONObject dataJsonObject = jsonObject.getJSONObject("data");
            JSONObject pageInfo = dataJsonObject.getJSONObject("paginator");
            int pageSize = pageInfo.getIntValue("length");
            int total = pageInfo.getIntValue("items");
            int pageNo = pageInfo.getIntValue("page");
            JSONArray datasJsonArray = dataJsonObject.getJSONArray("pageList");
            List<GoodVo> goodVos = new ArrayList<>();
            datasJsonArray.forEach(item -> {
                JSONObject itemJsonObject = (JSONObject) item;
                String goodId = itemJsonObject.getString("auctionId");
                String title = itemJsonObject.getString("title");
                title = StringUtils.replaceAll(title, "<span class=H>", "");
                title = StringUtils.replaceAll(title, "</span>", "");
                String shortTitle = title;
                String pic = itemJsonObject.getString("pictUrl");
                pic = StringUtils.startsWith(pic, "http:") ? "http:" + pic : pic;
                BigDecimal price = itemJsonObject.getBigDecimal("zkPrice");
                BigDecimal commission = itemJsonObject.getBigDecimal("tkCommonRate");
                String couponId = itemJsonObject.getString("couponActivityId");
                BigDecimal couponPrice = itemJsonObject.getBigDecimal("couponAmount");
                String couponConditionStr = itemJsonObject.getString("couponInfo");
                BigDecimal couponCondition = BigDecimal.ZERO;
                if(StringUtils.isNotEmpty(couponConditionStr) && !StringUtils.equals(couponConditionStr, "无")) {
                    couponConditionStr = StringUtils.replaceAll(couponConditionStr, "满\\d{1,}元减", "");
                    couponConditionStr = StringUtils.replaceAll(couponConditionStr, "元", "");
                    couponConditionStr = StringUtils.replaceAll(couponConditionStr, "无条件券", "");
                    couponCondition = new BigDecimal(couponConditionStr);
                }
                String couponEffectiveStartTime = itemJsonObject.getString("couponEffectiveStartTime");
                String couponEffectiveEndTime = itemJsonObject.getString("couponEffectiveEndTime");
                LocalDateTime couponStartTime = StringUtils.isEmpty(couponEffectiveStartTime) ? null : LocalDateTime.of(LocalDate.parse(itemJsonObject.getString("couponEffectiveStartTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalTime.of(0, 0, 0));
                LocalDateTime couponEndTime = StringUtils.isEmpty(couponEffectiveEndTime) ? null : LocalDateTime.of(LocalDate.parse(itemJsonObject.getString("couponEffectiveEndTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalTime.of(0, 0, 0));
                int sellNum = itemJsonObject.getIntValue("biz30day");
                String sellerId = itemJsonObject.getString("sellerId");
                String sellerName = itemJsonObject.getString("shopTitle");
                int tmall = itemJsonObject.getIntValue("userType");
                tmall = tmall == 1 ? 1 : 2;
                GoodVo goodVo = new GoodVo(
                        -1,
                        goodId,
                        title,
                        shortTitle,
                        "",
                        pic,
                        price,
                        commission,
                        0,
                        tmall,
                        sellNum,
                        couponId,
                        couponPrice,
                        couponCondition,
                        "",
                        couponStartTime,
                        couponEndTime,
                        sellerId,
                        sellerName,
                        0);
                goodVos.add(goodVo);
            });
            return PageResult.of(pageNo, pageSize, total, goodVos);
        }
        return PageResult.of(1, 80, 0);
    }

    /**
     * 阿里妈妈查询
     * @param keyword 查询关键字
     * @param pageNo  页码
     * @param pageSize 分页大小
     * @return 请求内容
     */
    public PageResult<GoodVo> search(String keyword, int pageNo, int pageSize) {
        return search(keyword, true, 9, pageNo, pageSize);
    }

    /**
     * 阿里妈妈查询
     * @param keyword  查询关键字
     * @param tmall   是否是天猫商店
     * @param sort    排序 9销量从高到低  4价格从低到高
     * @param pageNo  页码
     * @param pageSize 分页大小
     * @return 请求内容
     */
    public PageResult<GoodVo> search(String keyword, boolean tmall, int sort, int pageNo, int pageSize) {
        try {
            Url.UrlBuilder urlBuilder = Url.create();
            urlBuilder.url(ALIMAMA_SEARCH_URL)
                    .appendQuery("q", keyword)
                    .appendQuery("toPage", String.valueOf(pageNo))
                    .appendQuery("perPageSize", String.valueOf(pageSize))
                    .appendQuery("t", String.valueOf(System.currentTimeMillis()))
                    .appendQuery("freeShipment", String.valueOf(1))
                    .appendQuery("dpyhq", "1")
                    .appendQuery("shopTag", "yxjh,dpyhq");
            if(sort != -1) {
                urlBuilder.appendQuery("sortType", String.valueOf(sort));
                urlBuilder.appendQuery("queryType", String.valueOf(0));
            } else {
                urlBuilder.appendQuery("queryType", String.valueOf(2));
            }
            if(tmall) {
                urlBuilder.appendQuery("b2c", String.valueOf(1));
            }
            String url = urlBuilder.build().getUrl();
            HttpGet httpGet = new HttpGet(url);
            HttpResponse response = getHasCookieHttpClient().execute(httpGet);
            int statuCode = response.getStatusLine().getStatusCode();
            HttpEntity httpEntity = response.getEntity();
            if(statuCode == 200 && null != httpEntity) {
                String content = EntityUtils.toString(httpEntity, "UTF-8");
                return formatContent(content);
            }
        } catch(Exception e) {
            log.error("请求阿里妈妈查询异常", e);
        }
        return formatContent("");
    }
}
